/* eslint-disable */
import Dialog from "./dialog";
import Utils from "../core/utils";
import ArrayUtils from "../commons/array-utils";
import StringUtils from "../commons/string-utils";

import StringBuilder from "../core/string-builder";


/**
 * ajax封装（日常业务使用的 ajax）
 *
 * 对项目中的所有请求进行二次封装，做了一层总的代理，内容如下：
 * 1、默认显示加载条，除非手动禁用；
 * 2、业务处理出现错误，有默认的弹窗提示；
 * 3、DELETE请求，默认给确认窗口，需要用户确认后提交。
 *
 * ========================================================================
 */
//ajax start ------------------------------------------------------------

/**
 * ajax 执行器
 */
let executor = undefined;

/**
 * Layers 代理了全局的 ajax 请求
 *
 * 注意，这个函数包含序列化操作：字符串类型，去除前后空格；非字符类型，则格式化成字符串。
 *
 * 如果不想执行默认的格式化操作，可以直接调用 execute() 函数。
 *
 * @param request - ajax 配置
 * @returns {Promise<any>}
 */
const ajax = (request) => {
    let params = request.params;

    if (isNotEmpty(params)) {
        request.params = processRequestParams(params);
    }

    let data = request.data;
    if (isNotEmpty(data) && !(data instanceof FormData)) {
        request.data = processRequestParams(data);
    }

    return executor(request);
};

/**
 * 发送POST请求
 *
 * @param request - ajax配置
 * @returns 后台请求响应
 */
const post = (request) => {
    request.method = 'POST';
    return ajax(request);
};

/**
 * 发送GET请求
 *
 * @param request - ajax配置
 * @returns 后台请求响应
 */
const get = (request) => {
    request.method = 'GET';
    return ajax(request);
};

/**
 * 发送DELETE请求，自动给出弹窗提示
 *
 * @param request - ajax配置
 * @returns 后台请求响应
 */
const delete_ = (request) => {
    request.method = 'DELETE';
    return Dialog.confirm('是否确定删除？').then(() => {
        return ajax(request)
    });
};


/**
 * 发生PUT请求
 *
 * @param request - ajax配置
 * @returns 后台请求响应
 */
const put = (request) => {
    request.method = 'PUT';
    return ajax(request);
}


/**
 * 格式化参数
 *
 * 当前函数，对请求参数，进行了最基本的格式转换：
 *
 * 将所有参数转换成字符串，并去除所有空字符串。
 *
 * @param params - 请求参数
 * @returns 序列化之后数据 processRequestParams
 */
const toFormData = (params) => {
    const ret = new FormData();
    Object.keys(params).forEach(key => ret.append(key, params[key]));
    return ret;
}

/**
 * 格式化参数
 *
 * 当前函数，对请求参数，进行了最基本的格式转换：
 *
 * 将所有参数转换成字符串，并去除所有空字符串。
 *
 * @param params - 请求参数
 * @returns 序列化之后数据 processRequestParams
 */
const processRequestParams = (params) => {
    let ret = {};
    for (let key in params) {
        if (params.hasOwnProperty(key)) {
            let val = params[key];

            if (isEmpty(val)) {
                // do nothing
            } else if (typeof val === 'string') {
                // 字符串，自动去除前后空格
                val = val.trim();
                if (val.length > 0) {
                    ret[key] = val;
                }
            } else if (Array.isArray(val)) {
                // 数组用逗号拼接
                ret[key] = val.join(',');
            } else if (Date.prototype.isPrototypeOf(val)) {
                // 日期默认转 datetime 类型
                ret[key] = StringUtils.datetime(val);
            } else {
                // 其它类型转换成字符串
                ret[key] = val.toString();
            }
        }
    }
    return ret;
};


/**
 * 链式 ajax
 *
 * 顺序执行多个 ajax，只要中间有任何异常抛出，则直接抛到最后面的异常catch块，
 * 代码写法参考下列代码注释
 *
 * <code><pre>
 * linkedAjax()
 *      .then(action => {
 *          return action('test1').then(str => {
 *              console.log(str);
 *              return action;
 *          });
 *      }).then(action => {
 *          return action('test1').then(str => {
 *              console.log(str);
 *              return action;
 *          });
 *      }).catch(e=>{
 *           console.err(e);
 *      });
 * </pre></code>
 * @returns {Promise}
 */
const linkedAjax = () => {
    return Promise.resolve(ajax)
}

/**
 * 并行执行多个 ajax 请求
 *
 * @param requests - ajax 配置
 * @returns 各个请求响应组成的数组
 */
const multipleAjax = (requests) => {
    let all = [];
    for (let i = 0; i < requests.length; i++) {
        all.push(
            new Promise((resolve, reject) => {
                ajax(requests[i]).then(res => {
                    resolve(res);
                }).catch((err) => {
                    reject(err);
                });
            })
        )
    }
    return Promise.all(all);
};

/**
 * 将参数添加到请求路径中
 *
 * @param url - 地址
 * @param params - 请求参数
 * @returns GET 请求适用的 url
 */
const addParamsToUrl = (url, params) => {
    if (params === undefined) {
        return url;
    } else {
        const sb = new StringBuilder();
        sb.append(url);
        let idx = url.indexOf('?');
        if (idx < 0) {
            sb.append('?')
        } else if (idx !== url.length - 1) {
            if (url.charAt(url.length - 1) !== '&') {
                sb.append('&')
            }
        }

        const args = processRequestParams(params);
        for (let key in args) {
            if (args.hasOwnProperty(key)) {
                let v = args[key];
                if (isNotEmpty(v)) {
                    sb.append(key).append('=').append(encodeURIComponent(args[key])).append('&');
                }
            }
        }

        // 如果有强迫症，可以在这里去除最后一个 & 符号

        return sb.build();
    }
}

/**
 * 获取 url 中的参数，经过 url 解码
 *
 * @param url - 地址
 * @returns 获取 url 中的请求参数
 */
const getParamsOfUrl = (url) => {
    let res = {};
    let idx = url.lastIndexOf('?');
    if (idx > 0) {
        let p = url.substring(idx + 1, url.length);

        // 兼容这种格式：http://www.baidu.com?name=min&age=16#eg1#eg2
        let idx = p.indexOf('#');
        if (idx > 0) {
            p = p.substring(0, idx);
        }

        let arr = p.split('&');
        for (let i = 0; i < arr.length; i++) {
            let a = arr[i].split('=');
            if (a.length > 1) {
                res[a[0]] = decodeURI(a[1])
            }
        }
    }
    return res;
}

/**
 * 请求上下文路径
 */
let context_path = '';

/**
 * 请求上下文
 */
const contextPath = () => {
    return context_path;
}

/**
 * 当前组件可供调整的属性
 */
export class Setting {
    /**
     * 设置数据查询接口
     *
     * @param val - 数据查询函数
     */
    setExecutor(val) {
        executor = val
    }

    /**
     * 请求上下文路径
     *
     * @param path -上下文路径
     */
    setContextPath(path) {
        context_path = path;
    }
}


/**
 * 通用工具
 *
 * @constructor
 */
const Layers = {
    // common tools
    ...Dialog, ...Utils, ...ArrayUtils,

    // ajax
    multipleAjax, linkedAjax, processRequestParams,
    ajax, get, post, delete: delete_, put,
    addParamsToUrl, getParamsOfUrl, contextPath
}

// 直接挂在 window 对象上，方便全局使用
window['Layers'] = Layers;

// 只是为了初始化
export default Layers;